import { observable, action, computed } from 'mobx';
import {
    Auth, User, LoginParam, PasswordParam,
} from '@/type/Auth';
import { setAuth, getAuth } from '@/api';
import permissionPersist from '@/persists/permissionPersist';
import auth from '@/api/authApi';
import { AxiosRequestConfig } from 'axios';
import { persist } from 'mobx-persist';
import { Permission } from '@/type/Permission';

export default class AuthStore {
    @persist('object') @observable auth: Auth = {
        token: '',
    };

    @persist('object') @observable user?: User = {
        first_name: '',
        last_name: '',
        username: '',
    };

    @action
    public async login(param: LoginParam): Promise<string | boolean> {
        const token = await auth.login(param);
        if (!token) return false;
        this.auth.token = token;
        setAuth(this.authHeader);
        await this.setLoggedUserPermission();
        return token;
    }

    @action
    public async otpLogin(otp: string): Promise<string | boolean> {
        const token = await auth.otpLogin(otp);
        if (!token) return false;
        this.auth.token = token;
        setAuth(this.authHeader);
        await this.setLoggedUserPermission();
        return token;
    }

    @action
    public setAuth(): void {
        setAuth(this.authHeader);
    }

    @action
    public clearAuth(): void {
        setAuth({});
    }

    @action
    private setPermissions(permissions: Permission[]): void {
        permissionPersist.set(permissions);
    }

    @action
    public hasPermission(featureName: string, ability: string): boolean {
        return permissionPersist
            .get()
            .find((p) => p.feature_name === featureName && p.ability === ability) != null;
    }

    @action
    public async logout() {
        await auth.logout();
        this.forceLogout();
    }

    @action
    public async forceLogout() {
        this.auth = {
            token: '',
        };
        this.clearAuth();
        this.setPermissions([]);
        this.user = undefined;
    }

    @action
    public async getUser(): Promise<User> {
        this.user = await auth.getUser();
        return this.user;
    }

    @action
    public async updateUser(user: Partial<User & PasswordParam>): Promise<User> {
        this.user = await auth.updateUser({ ...this.user, ...user });
        return this.user;
    }

    @action
    public async setLoggedUserPermission(): Promise<Permission[]> {
        const permissions = await auth.getLoggedUserPermission();
        this.setPermissions(permissions);
        return permissions;
    }

    @computed
    get authHeader(): AxiosRequestConfig {
        return {
            headers: {
                Authorization: `Bearer ${this.auth.token}`,
                'Access-Control-Allow-Origin': '*',
            },
        };
    }

    @computed
    get isLogged(): boolean {
        const token: AxiosRequestConfig = getAuth();
        return !!token.headers && token.headers.Authorization !== 'Bearer ';
    }
}
